﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ParametresPassage
{
    //1. Type Rérérence
    class IntHolderClass
    {
        public IntHolderClass() { }
        public IntHolderClass(int k) { i = k; }
        public int i;
    }



    //2.Type Valeur:
    struct IntHolderStruct
    {
        // public IntHolderStruct() { }
        public IntHolderStruct(int i) { this.i = i; }
        public int i;
    }


    class Program
    {
        static void Main(string[] args)
        {
            //1. Type Rérérence et Valeur
            StringBuilder f = new StringBuilder();
            f.Append("hello");
            Console.WriteLine("f initial: {0}", f);

            StringBuilder s = f;
            f = null;
            Console.WriteLine("s initial: {0}", s);
            Console.WriteLine("f après: {0}", f);


            // IntHolderClass First= new IntHolderClass();
            IntHolderStruct First = new IntHolderStruct();
            First.i = 5;
            //IntHolderClass Second=First;
            IntHolderStruct Second = First;
            First.i = 6;
            Console.WriteLine("\nFirst après: {0}", First.i);
            Console.WriteLine("Second après: {0}", Second.i);

            //2. Passage de parametre type Ref

            StringBuilder x = new StringBuilder();
            x.Append("Bobo");
            Foo(x); //Une copie de Reference x sera  créé (sur pile), qui va pointer d'abord sur l'objet x (sur tas)? Mais après, affecté par Null (dans la fonction appelée)
            Console.WriteLine("\nStringBuilder x became null? {0};", x == null); // donc, la Réfence de x pointe tjs sur l'objet x "Bobo"
            Console.WriteLine("x après: {0}", x);

            IntHolderClass h0 = new IntHolderClass();
            h0.i = 5;
            FooRef(h0);
            Console.WriteLine("\nClasse après 0: {0}", h0.i);

            //3. Passage de paramètre type Valeur
            IntHolderStruct h = new IntHolderStruct();
            h.i = 5;
            FooValeur(h);
            Console.WriteLine("\nStructure après: {0}", h.i);

            //4.5. Passage de parametre (ref ou valeur) par Ref: à ajouter le mot ref pour tester (etape 2,3)

            // Passage de parametre type Ref par Ref ou par Valeur: C'est presque pareil car dans la méthode appelante, 
            //on a soit une , soit 2 références, mais qui vont tjs pointer sur le meme contenu objet:  //Les deux variables partagent le même emplacement de stockage
            //Donc la manipulation de cet objet via ces reférences donne le meme résultat. Mais voir maintenant au cas:

            //6. quelle est la différence entre passer un objet valeur par référence et passer un objet référence par valeur ?

            IntHolderStruct y = new IntHolderStruct();
            y.i = 5;
            Foo6Val(ref y);
            Console.WriteLine("\nAutre structure après: {0}", y.i);

            IntHolderClass y1 = new IntHolderClass();
            y1.i = 5;
            Foo6Ref(y1); // il y aura une copie de référence
            // Foo6Ref(ref y1); // c'est la même référence qui sera manipulé, donc l'objet sera modifiable
            Console.WriteLine("IntHolderClass après: {0}", y1.i);

            Console.ReadKey();
        }

        static void FooValeur(IntHolderStruct s)
        {
            s.i = 100;
        }
        static void FooValeur(ref IntHolderStruct s)
        {
            s.i = 100;
        }

        static void FooRef(IntHolderClass s)
        {
            s.i = 100;
        }
        static void FooRef(ref IntHolderClass s)
        {
            s.i = 100;
        }

        static void Foo6Val(ref IntHolderStruct x)
        {
            x = new IntHolderStruct(-1);
        }

        static void Foo6Ref(IntHolderClass x)
        {
            x = new IntHolderClass(-1);
        }

        static void Foo6Ref(ref IntHolderClass x)
        {
            x = new IntHolderClass(-1);
        }

        static void Foo(StringBuilder s)
        {
            s = null;
            //cependant la valeur d'une variable de type référence est la référence - 
            //si deux variables de type référence pointent vers le même objet, alors les modifications apportées 
            //aux données de l'objet seront visibles via les deux variables: On peut donc modifier l'objet via la copie de référence
            s.Append(" va bien");
        }
        static void Foo(ref StringBuilder s)
        {
            s = null;
        }


    }
}
